﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// Kuwahara enstrengthens edges by preserving structures
    /// </summary>
    public class Kuwahara : BaseImageFilter
    {
        protected int m_nSize = 3;

        /// <summary>
        /// default constructor
        /// </summary>
        public Kuwahara()
        {
        }

        /// <summary>
        /// primary constructor, specify size directly
        /// </summary>
        /// <param name="_nSize"></param>
        public Kuwahara(int _nSize)
        {
            m_nSize = _nSize;
        }

        /// <summary>
        /// used by clone to create a deep copy
        /// </summary>
        /// <param name="_kuwahara"></param>
        internal Kuwahara(Kuwahara _kuwahara)
        {
            this.m_nSize = _kuwahara.m_nSize;
        }

        /// <summary>
        /// Gets or sets the size.
        /// </summary>
        /// <value>The size.</value>
        public int Size
        {
            get { return m_nSize; }
            set { m_nSize = value; }
        }

        /// <summary>
        /// Executes this filter
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            UnsafeBitmap _TempBitmap = (UnsafeBitmap)_bitmap.Clone();
            UnsafeBitmap TempBitmap = new UnsafeBitmap(_TempBitmap);

            UnsafeBitmap _NewBitmap = _bitmap;
            UnsafeBitmap NewBitmap = new UnsafeBitmap(_NewBitmap);

            /*Graphics NewGraphics = Graphics.FromImage(NewBitmap);
            NewGraphics.DrawImage(TempBitmap, new Rectangle(0, 0, TempBitmap.Width, TempBitmap.Height), new System.Drawing.Rectangle(0, 0, TempBitmap.Width, TempBitmap.Height), System.Drawing.GraphicsUnit.Pixel);
            NewGraphics.Dispose();*/

            int nHeight = TempBitmap.Height;
            int nWidth = TempBitmap.Width;

            Random TempRandom = new Random();
            int[] aApertureMinX = { -(m_nSize / 2), 0, -(m_nSize / 2), 0 };
            int[] aApertureMaxX = { 0, (m_nSize / 2), 0, (m_nSize / 2) };
            int[] aApertureMinY = { -(m_nSize / 2), -(m_nSize / 2), 0, 0 };
            int[] aApertureMaxY = { 0, 0, (m_nSize / 2), (m_nSize / 2) };

            for (int x = 0; x < nWidth; ++x)
            {
                for (int y = 0; y < nHeight; ++y)
                {
                    int[] aRValue = { 0, 0, 0, 0 };
                    int[] aGValue = { 0, 0, 0, 0 };
                    int[] aBValue = { 0, 0, 0, 0 };
                    int[] NumPixels = { 0, 0, 0, 0 };
                    int[] MaxRValue = { 0, 0, 0, 0 };
                    int[] MaxGValue = { 0, 0, 0, 0 };
                    int[] MaxBValue = { 0, 0, 0, 0 };
                    int[] MinRValue = { 255, 255, 255, 255 };
                    int[] MinGValue = { 255, 255, 255, 255 };
                    int[] MinBValue = { 255, 255, 255, 255 };
                    for (int i = 0; i < 4; ++i)
                    {
                        for (int x2 = aApertureMinX[i]; x2 < aApertureMaxX[i]; ++x2)
                        {
                            int TempX = x + x2;
                            if (TempX >= 0 && TempX < nWidth)
                            {
                                for (int y2 = aApertureMinY[i]; y2 < aApertureMaxY[i]; ++y2)
                                {
                                    int TempY = y + y2;
                                    if (TempY >= 0 && TempY < nHeight)
                                    {
                                        Color TempColor = TempBitmap.GetPixel(TempX, TempY);
                                        aRValue[i] += TempColor.R;
                                        aGValue[i] += TempColor.G;
                                        aBValue[i] += TempColor.B;
                                        if (TempColor.R > MaxRValue[i])
                                        {
                                            MaxRValue[i] = TempColor.R;
                                        }
                                        else if (TempColor.R < MinRValue[i])
                                        {
                                            MinRValue[i] = TempColor.R;
                                        }

                                        if (TempColor.G > MaxGValue[i])
                                        {
                                            MaxGValue[i] = TempColor.G;
                                        }
                                        else if (TempColor.G < MinGValue[i])
                                        {
                                            MinGValue[i] = TempColor.G;
                                        }

                                        if (TempColor.B > MaxBValue[i])
                                        {
                                            MaxBValue[i] = TempColor.B;
                                        }
                                        else if (TempColor.B < MinBValue[i])
                                        {
                                            MinBValue[i] = TempColor.B;
                                        }
                                        ++NumPixels[i];
                                    }
                                }
                            }
                        }
                    }
                    int j = 0;
                    int MinDifference = 10000;
                    for (int i = 0; i < 4; ++i)
                    {
                        int CurrentDifference = (MaxRValue[i] - MinRValue[i]) + (MaxGValue[i] - MinGValue[i]) + (MaxBValue[i] - MinBValue[i]);
                        if (CurrentDifference < MinDifference && NumPixels[i] > 0)
                        {
                            j = i;
                            MinDifference = CurrentDifference;
                        }
                    }

                    Color MeanPixel = Color.FromArgb(aRValue[j] / NumPixels[j],
                        aGValue[j] / NumPixels[j],
                        aBValue[j] / NumPixels[j]);
                    NewBitmap.SetPixel(x, y, MeanPixel);
                }
            }

            NewBitmap.Dispose();
            TempBitmap.Dispose();
            return _bitmap;
        }

        /// <summary>
        /// used to create a deep copy
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new Kuwahara(this);
        }
    }
}

